using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using XcoAppSpaces.Transport.Sockets.Auth;
using XcoAppSpaces.Transport.Sockets.Auth.Contract;
using System.Threading.Tasks;
using System.Threading;
using System.Net;

namespace test.XcoAppSpaces.Transport.Sockets.Auth
{
	[TestFixture]
	public class CheckMultipleInvalidAttemptsTests
	{
		private CheckMultipleInvalidAttempts sut;
		private EndPoint resultAddress;

		[SetUp]
		public void SetUp()
		{
			sut = new CheckMultipleInvalidAttempts(1000);
			sut.Inject(new SecuritySettings { NumInvalidAttemptsForBlacklist = 3, SecondsAfterConnectionRemovedFromGraylist = 3 });
			sut.Out_InvalidAddress += _ => resultAddress = _;
			resultAddress = null;
		}

		[Test]
		public void NumberOfAttemptsAboveLimit_AddressGetsInvalid()
		{
			using (var connections = new ConnectedTcpClientPair())
			{
				sut.In_SuspiciousConnection(connections.ReceivingClient);
				sut.In_SuspiciousConnection(connections.ReceivingClient);
				sut.In_SuspiciousConnection(connections.ReceivingClient);

				Assert.IsTrue(SpinWait.SpinUntil(() => resultAddress != null, 1000));
				Assert.AreEqual(connections.ReceivingClient.Client.RemoteEndPoint, resultAddress);
			}
		}

		[Test]
		public void NumberOfAttemptsUnderLimit_AddressDoesntGetInvalid()
		{
			using (var connections = new ConnectedTcpClientPair())
			{
				sut.In_SuspiciousConnection(connections.ReceivingClient);
				sut.In_SuspiciousConnection(connections.ReceivingClient);

				Assert.IsFalse(SpinWait.SpinUntil(() => resultAddress != null, 1000));
			}
		}

		[Test]
		public void NumberOfAttemptsAreResetByValidConnection()
		{
			using (var connections = new ConnectedTcpClientPair())
			{
				sut.In_SuspiciousConnection(connections.ReceivingClient);
				sut.In_SuspiciousConnection(connections.ReceivingClient);
				sut.In_ValidConnection(connections.ReceivingClient);
				sut.In_SuspiciousConnection(connections.ReceivingClient);
				sut.In_SuspiciousConnection(connections.ReceivingClient);
				
				Assert.IsFalse(SpinWait.SpinUntil(() => resultAddress != null, 1000));
			}
		}

		[Test]
		public void NumberOfAttemptsAreResetByExpiry()
		{
			using (var connections = new ConnectedTcpClientPair())
			{
				sut.In_SuspiciousConnection(connections.ReceivingClient);
				sut.In_SuspiciousConnection(connections.ReceivingClient);
				Thread.Sleep(4000);
				sut.In_SuspiciousConnection(connections.ReceivingClient);
				sut.In_SuspiciousConnection(connections.ReceivingClient);

				Assert.IsFalse(SpinWait.SpinUntil(() => resultAddress != null, 1000));
			}
		}
	}
}
